// 用户模型

package model

import (
	"encoding/base64"
	"github.com/jinzhu/gorm"
	"goblog/utils/errmsg"
	"golang.org/x/crypto/scrypt"
	"log"
)

type User struct {
	gorm.Model
	Username string `gorm:"type:varchar(20);not null" json:"username" validate:"required,min=4,max=12"` //postman中传参就得用username这就叫绑定  不为空最小4最大12
	Password string `gorm:"type:varchar(20);not null" json:"password" validate:"required,min=6,max=20"`
	Email    string `gorm:"type:varchar(20);not null" json:"email"`
	Role     int    `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2"` // 多对一的关系，通过 RoleID 找到 Role 表中的数据
	Avatar   string `gorm:"type:varchar(20);not null" json:"avatar"`                  //头像

}

// 查询用户

func CheckUser(name string) (code int) {
	var users User
	db.Select("id").Where("username =?", name).First(&users) //name是入参
	if users.ID != 0 {
		return errmsg.ERROR_USERNAME_USED //1001
	}
	return errmsg.SUCCESS
}

// 添加用户

func CreateUser(data *User) int { //返回的int就是状态码
	//data.Password = ScryptPW(data.Password) 在写进数据库之前加盐——也可以使用钩子函数这里我们选择使用钩子函数
	err := db.Create(&data).Error
	if err != nil {
		return errmsg.ERROR //400
	}
	return errmsg.SUCCESS
}

// 查询用户列表
// 涉及到列表的就要把分页做好

func GetUsers(pageSize int, pageNum int) ([]User, int) { //返回一个User的切片pageSize是多少一页就有多少
	var users []User //var一个users等于他的切片                                                         //定义一个users等于上面的切片
	var total int
	err = db.Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users).Count(&total).Error //Limit做分页 Offset偏移量
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, 0
	}
	return users, total
}

//编辑用户（限定是密码以外的比如昵称e_mail）
//map更新会更新其中有变化的属性而struct是更新有变化且非零的值（但是次项目中我们role设置有0）

func EditUser(id int, data *User) int {
	var user User                           //var一个user是User的模型保持简洁
	var maps = make(map[string]interface{}) //interface是接口类型
	maps["username"] = data.Username        //给maps赋值
	maps["role"] = data.Role
	err = db.Model(&user).Where("id = ?", id).Update(maps).Error //从db.Model中的User更新
	if err != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCESS
}

//密码加密
//一般技术比较成熟比较常见的时bcrypt
//但是本次采用scrypt更加的专业

//钩子函数

func (u *User) BeforeSave() {
	u.Password = ScryptPW(u.Password) //在Save之前加
}

func ScryptPW(password string) string { //password入参再把加密后端密码传出都是string
	const KeyLen = 10
	salt := make([]byte, 8)
	salt = []byte{12, 32, 4, 6, 66, 22, 222, 11}                           //加盐中的数字是自定义
	HashPw, err := scrypt.Key([]byte(password), salt, 16384, 8, 1, KeyLen) //N的值规定为2^n,会输出一个byte（HashPw）和一个error
	if err != nil {
		log.Fatal(err)
	}
	finalPw := base64.StdEncoding.EncodeToString(HashPw)
	return finalPw
}

//删除用户

func DeleteUser(id int) int {
	var user User
	err = db.Where("id = ?", id).Delete(&user).Error
	if err != nil {
		return errmsg.ERROR
	}
	return errmsg.SUCCESS
}

// 登陆验证
func CheckLogin(username string, password string) int { //返回的int代表成功与否
	var user User
	db.Where("username = ?", username).First(&user)
	if user.ID == 0 {
		return errmsg.ERROR_USER_NOT_EXIST
	}
	if ScryptPW(password) != user.Password {
		return errmsg.ERROR_PASSWORD_WRONG
	}
	if user.Role != 2 {
		return errmsg.ERROR_USER_NO_RIGHT
	}
	return errmsg.SUCCESS
}
